/*
DirBkgndExt.
Copyright (C) 2007 sevenever  

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
// FileContextMenuExt.cpp : Implementation of CFileContextMenuExt
#include "stdafx.h"
#include "DirBkgndExt.h"
#include "FileContextMenuExt.h"
#include "config.h"

extern config cfg;
/////////////////////////////////////////////////////////////////////////////
// CFileContextMenuExt


HRESULT CFileContextMenuExt::Initialize ( LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hProgID )
{
	FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
	STGMEDIUM stg = { TYMED_HGLOBAL };
	HDROP hDrop;

	// find CF_HDROP .
	if ( FAILED( pDataObj->GetData ( &fmt, &stg ))){
		// Nope! Return an "invalid argument" error back to Explorer.
		return E_INVALIDARG;
	}
	
	hDrop = (HDROP) GlobalLock ( stg.hGlobal );

	// Check Must NOT NULL.
	if ( NULL == hDrop ){
		return E_INVALIDARG;
	}
	// ensure atlast one filename.
	UINT uNumFiles = DragQueryFile ( hDrop, 0xFFFFFFFF, NULL, 0 );
	if ( 0 == uNumFiles ){
		GlobalUnlock ( stg.hGlobal );
		ReleaseStgMedium ( &stg );
		return E_INVALIDARG;
	}
	HRESULT hr = S_OK;

	// save first filename to m_szFile
	if ( 0 == DragQueryFile ( hDrop, 0, m_szFile, MAX_PATH )){
		hr = E_INVALIDARG;
	}
	GlobalUnlock ( stg.hGlobal );
	ReleaseStgMedium ( &stg );
	return hr;
}

HRESULT CFileContextMenuExt::QueryContextMenu ( HMENU hmenu,UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags )
{ 
	unsigned long code;

	if ( uFlags & CMF_DEFAULTONLY ) 
	{ 
		return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 ); 
	} 
    code = 0;
	if(cfg.showCopyFilePath){
		InsertMenu ( hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, _T("Copy file path") );
		offsetMap[code]=0;
		code++;
	}

	if(cfg.showRegDllMenu){
		//dll 
		TCHAR ext[5];
		//copy file extension 
		_tcsncpy(ext, m_szFile + _tcslen(m_szFile) - 4, 4);
		ext[4] = 0x0;
		//make upper
		_tcsupr(ext);
		if( _tcscmp(ext, _T(".DLL")) == NULL ){
			//Load library
			HMODULE hModule = LoadLibrary(m_szFile);
			if(hModule){
				//Check if  exists
				if(GetProcAddress(hModule, "DllRegisterServer")){
					//add another two menu items
					InsertMenu ( hmenu, uMenuIndex+1, MF_BYPOSITION, uidFirstCmd+1, _T("(Un)Register this dll") );
					offsetMap[code]=1;
					code++;
				}
				FreeLibrary(hModule);
			}
		}
	}
	return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, code );
}

HRESULT CFileContextMenuExt::GetCommandString( UINT idCmd, UINT uFlags,UINT* pwReserved, LPSTR pszName, UINT cchMax ) 
{
	USES_CONVERSION; 
	//idCmd the offset of command id must be 0:Copy file path or (Un)RegisterDll
	if ( idCmd > 1 ) 
		return E_INVALIDARG; 
	
	// return help text
	if ( uFlags & GCS_HELPTEXT ) 
	{
		LPCTSTR szText;
		switch(idCmd){
			case 0:szText = _T("Copy the full file name to clipboard");break;//Copy file path
			case 1:szText = _T("Register(Unregister with shift down) COM dll");break;//RegisterDll
			default:break;
		}
		if ( uFlags & GCS_UNICODE )
		{ 
			lstrcpynW ( (LPWSTR) pszName, T2CW(szText), cchMax ); 
		}
		else
		{
			lstrcpynA ( pszName, T2CA(szText), cchMax ); 
		}
		return S_OK;	
	} 
	return E_INVALIDARG; 
}

HRESULT CFileContextMenuExt::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo )
{
	TCHAR szFilename[MAX_PATH];				//filename buffer
	SHORT sKeyState;						//Shift key state
	PTCHAR pFilename;						//filename without path

	if ( 0 != HIWORD( pCmdInfo->lpVerb ))
        return E_INVALIDARG;

	//get command id
	UINT idCmd = LOWORD(pCmdInfo->lpVerb);
	bool shiftdown;
	//Is shift key pressed down?
	sKeyState = GetKeyState(VK_SHIFT);
	if( sKeyState & 0xFF00 ) {
		shiftdown = true;
	} else {
		shiftdown = false;
	}

	switch(offsetMap[idCmd]){
		case 0:{//Copy file path
			if( shiftdown ) {
				pFilename = m_szFile + _tcslen(m_szFile);
				while( pFilename != m_szFile && *pFilename != _T('\\') ) {
					pFilename--;
				}
				if(*pFilename == _T('\\')) {
					pFilename++;
				}
				_tcscpy(szFilename,pFilename);
			} else {
				_tcscpy(szFilename,m_szFile);
			}
			//Malloc memory
			HANDLE hGlobalMemory = GlobalAlloc(GHND, (_tcslen(szFilename) + 1) * 2);
			//Lock the global memory
			LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory);
			//Copy data to globa memory
			_tcscpy((PTCHAR)lpGlobalMemory,szFilename);
			//Unlock the global memory
			GlobalUnlock(hGlobalMemory); 
			//Get safe window handler
			::OpenClipboard(pCmdInfo->hwnd); 
			::EmptyClipboard();
			::SetClipboardData(CF_UNICODETEXT, hGlobalMemory);
			::CloseClipboard(); 
			break;//Copy file path
			}
		case 1:{//RegisterDll
			//Load library
			bool succFlg=false;;
			HMODULE hModule = LoadLibrary(m_szFile);
			if(hModule){
				FARPROC pfun;
				if( shiftdown ) {
					if(pfun = GetProcAddress(hModule, "DllUnregisterServer")){
						if(S_OK == pfun()){
							succFlg = true;
						}
					}
				}else{
					if(pfun = GetProcAddress(hModule, "DllRegisterServer")){
						if(S_OK == pfun()){
							succFlg = true;
						}
					}
				}
				FreeLibrary(hModule);
			}
			if(succFlg){
				MessageBox(NULL,_T("Action succeed"),_T("shellext"),MB_OK | MB_ICONINFORMATION);
			}else{
				MessageBox(NULL,_T("Action failed"),_T("shellext"),MB_OK | MB_ICONERROR);
			}
			break;//RegisterDll
			}
		default:break;
	}
	return S_OK;
}